﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using __Able.Network.Connection;
using __Able.Network.Packets;

namespace __Able.Network.Threading
{
    /// <summary>
    /// 重发包触发器
    /// </summary>
    public class ResendTrigger : IRunable
    {
        private Channel channel;
        /// <summary>
        /// 单位: ms
        /// </summary>
        public const long TIMEOUT_SEND = 5000;
        // 超时队列
        private List<_OutPacket> sendQueue;

        public ResendTrigger(Channel channel)
        {
            this.channel = channel;
            sendQueue = new List<_OutPacket>();
            ThreadExcutor.RegisterIntervalObject(this, this, TIMEOUT_SEND, true);
        }
        /// <summary>
        /// 添加一个包到超时队列
        /// </summary>
        /// <param name="packet">The packet.</param>
        public void Add(_OutPacket packet, string portName)
        {
            packet.PortName = portName;
            sendQueue.Add(packet);
        }
        /// <summary>
        /// 清空重发队列
        /// </summary>
        public void Clear()
        {
            sendQueue.Clear();
        }
        /// <summary>
        /// 得到超时队列的第一个包，不把它从队列中删除
        /// </summary>
        /// <returns></returns>
        public _OutPacket Get()
        {
            if (sendQueue.Count > 0)
            {
                return sendQueue.First();
            }
            return null;
        }
        /// <summary>
        /// 得到超时队列的第一个包，并把它从队列中删除
        /// </summary>
        /// <returns></returns>
        public _OutPacket Remove()
        {
            if (sendQueue.Count > 0)
            {
                _OutPacket packet = sendQueue.First();
                sendQueue.Remove(packet);
                //portName = toPort[packet];
                //toPort.Remove(packet);
                return packet;
            }
            return null;

        }
        /// <summary>
        /// 删除ack对应的请求包
        /// </summary>
        /// <param name="ack">The ack.</param>
        public void Remove(_InPacket ack)
        {
            var outPacket = sendQueue.Where(p => p.Equals(ack)).FirstOrDefault();
            if (outPacket != null)
            {
                sendQueue.Remove(outPacket);
            }
        }
        /// <summary>
        /// 得到下一个包的超时时间
        /// 下一个包的超时时间，如果队列为空，返回一个固定值
        /// </summary>
        /// <returns></returns>
        private long GetTimeoutLeft()
        {
            _OutPacket packet = Get();
            if (packet == null)
            {
                return TIMEOUT_SEND;
            }
            else
            {
                return packet.TimeOut - Utils.Util.GetTimeMillis(DateTime.Now);
            }
        }
        /// <summary>
        /// 触发超时事件
        /// </summary>
        /// <param name="packet">The packet.</param>
        private void FireOperationTimeOutEvent(_OutPacket packet, string portName)
        {
            ErrorPacket error = new ErrorPacket(ErrorPacketType.ERROR_TIMEOUT, channel.User);
            error.TimeOutPacket = packet;
            error.Header = packet.Header;
            error.Family = packet.GetFamily();
            error.ConnectionId = portName;
            channel.PacketManager.AddIncomingPacket(error, portName);
        }
        /// <summary>
        /// 
        /// </summary>
        public bool IsRunning
        {
            get;
            private set;
        }
        public WaitHandle WaitHandler { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        /// <param name="timedOut"></param>
        public void Run(object state, bool timedOut)
        {
            if (IsRunning == false)
            {
                lock (this)
                {
                    if (!IsRunning)
                    {
                        IsRunning = true;
                        long t = GetTimeoutLeft();
                        while (t <= 0)
                        {
                            _OutPacket packet = Remove();
                            IConnection conn = channel.ConnectionManager.ConnectionPool.GetConnection(packet.PortName);
                            if (conn != null && packet != null && !conn.Policy.IsReplied(packet, false))
                            {
                                if (packet.NeedResend())
                                {
                                    // 重发次数未到最大，重发
                                    channel.PacketManager.SendPacketAnyway(packet, packet.PortName);
                                }
                                else
                                {
                                    // 触发操作超时事件
                                    FireOperationTimeOutEvent(packet, packet.PortName);
                                }
                            }
                            t = GetTimeoutLeft();
                        }
                        IsRunning = false;

                        // 继续等待 t 时间后再执行 // 先反注册原来的线程
                        this.RegisterdHandler.Unregister(this.WaitHandler);
                        ThreadExcutor.RegisterIntervalObject(this, this, t, true);
                    }
                }
            }
        }

        public System.Threading.RegisteredWaitHandle RegisterdHandler
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            if (this.WaitHandler != null && this.RegisterdHandler != null)
            {
                RegisterdHandler.Unregister(this.WaitHandler);
            }
        }
    }
}
